package com.snack.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.StringArrayHandler;
import org.apache.commons.dbutils.handlers.StringArrayListHandler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 数据库事务处理帮助类。
 * <p>
 * 典型的调用方法如下：
 * <br>
 * <pre>
 * DbTransaction dbc = new DbTransaction();
 * try {
 *     dbc.connect();
 *     dbc.begin();
 *     
 *     dbc.execute("select ...", new Object[]{...});
 *     dbc.execute("insert into ...", ...);
 *     dbc.execute("insert into ...");
 *     
 *     String[] tmp1 = dbc.find("select ...", new Object[]{...});
 *     System.out.println( org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(tmp1) );
 *     
 *     List<Object[]> params = new ArrayList<Object[]>();
 *     params.add(new Object[]{3213, "20080920101111"});
 *     params.add(new Object[]{3214, "20080920101111"});
 *     params.add(new Object[]{3215, "20080920101111"});
 *  
 *     dbc.batch("insert into ... values (?, ?)", params);
 *  
 *     List<String[]> tmp2 = dbc.query("select * from ...");
 *     System.out.println( org.apache.commons.lang.builder.ToStringBuilder.reflectionToString(tmp2) );
 *     
 *     dbc.execute("delete from ...", new Object[]{...});
 *          
 *     dbc.commit();
 * } catch (Exception e) {
 *     dbc.rollback();
 *     throw e;
 * } finally {
 *     dbc.close();
 * }
 * </pre>
 * <p>
 * Copyright: Copyright (c) Feb 6, 2009 3:39:21 PM
 * <p>
 * Company: 北京宽连十方数字技术有限公司
 * <p>
 * Author: chengyao
 * <p>
 * Version: 1.0
 * <p>
 */
public class DbTransaction {

    /** logger */
    private static final Log logger = LogFactory.getLog(DbTransaction.class);

    /** 数据库连接 */
    private Connection conn = null;

    /** 是否自动提交 */
    private boolean isAutoCommit;
    
    /** QueryRunner对象 */
    private QueryRunner run = null;

    /**
     * 初始化时初始化QueryRunner对象
     */
    public DbTransaction() {
        run = new QueryRunner();
    }
    
    /**
     * 建立数据库连接
     * @throws SQLException - 如果不能建立连接
     */
    public void connect() throws SQLException {
        try {
            conn = DbHelper.ds.getConnection();
        } catch (SQLException ex) {
            logger.error("get connection error!", ex);
            throw ex;
        }
    }

    /**
     * 事务生命周期开始
     * @throws SQLException SQL异常
     */
    public void begin() throws SQLException {
        try {
            isAutoCommit = conn.getAutoCommit();
            conn.setAutoCommit(false);
        } catch (SQLException ex) {
            logger.error("begin transaction error!", ex);
            throw ex;
        }
    }

    /**
     * 获取数据库连接
     * @return 数据库连接对象
     */
    public Connection getConnection() {
        return conn;
    }

    /**
     * 结束事务生命周期，提交所有变更
     * @throws SQLException SQL异常
     */
    public void commit() throws SQLException {
        try {
            conn.commit();
            conn.setAutoCommit(isAutoCommit);
        } catch (SQLException ex) {
            logger.error("commit transaction error!", ex);
            throw ex;
        }
    }

    /**
     * 事务回滚
     */
    public void rollback() {
        try {
            conn.rollback();
            conn.setAutoCommit(isAutoCommit);
        } catch (SQLException ex) {
            logger.error("rollback transaction error!", ex);
        }
    }

    /**
     * 判断是否为自动加入数据模式
     * @return 是否为自动提交
     * @throws SQLException SQL异常
     */
    public boolean getAutoCommit() throws SQLException {
        boolean result = false;
        try {
            result = conn.getAutoCommit();
        } catch (SQLException ex) {
            logger.error("get auto commit status error!", ex);
            throw ex;
        }
        return result;
    }

    /**
     * sql执行操作，用于数据更新，主要是Update，Insert，delete
     * @param sql 要执行的sql语句
     * @return 影响的行数
     * @throws SQLException 捕捉错误
     */
    public int execute(String sql) throws SQLException {
        return run.update(conn, sql);
    }
    
    /**
     * sql执行操作，用于数据更新，主要是Update，Insert，delete
     * @param sql 要执行的sql语句
     * @param param 参数对象
     * @return 影响的行数
     * @throws SQLException 捕捉错误
     */
    public int execute(String sql, Object param) throws SQLException {
        return run.update(conn, sql, param);
    }
    
    /**
     * sql执行操作，用于数据更新，主要是Update，Insert，delete
     * @param sql 要执行的sql语句
     * @param params 参数数组对象
     * @return 影响的行数
     * @throws SQLException 捕捉错误
     */
    public int execute(String sql, Object... params) throws SQLException {
        return run.update(conn, sql, params);
    }
    
    /**
     * 批处理执行sql
     * @param sql 要执行的SQL语句
     * @param params 参数数组对象
     * @return The number of rows updated per statement.
     * @throws SQLException SQL异常
     */
    public int[] batch(String sql, List<Object[]> params) throws SQLException {
        Object[][] p = new Object[params.size()][];
        for (int i = 0; i < params.size(); i++) {
            p[i] = params.get(i);
        }
        return run.batch(conn, sql, p);
    }
    
    /**
     * 查找单条记录
     * @param sql 要执行的SQL语句
     * @return 如果查询不到记录，返回null
     * @throws SQLException SQL异常
     */
    public String[] find(String sql) throws SQLException {
        return find(sql, (Object[]) null);
    }
    
    /**
     * 查找单条记录
     * @param sql 要执行的SQL语句
     * @param param 参数对象
     * @return 如果查询不到记录，返回null
     * @throws SQLException SQL异常
     */
    public String[] find(String sql, Object param) throws SQLException {
        return find(sql, new Object[] { param });
    }
    
    /**
     * 查找单条记录
     * @param sql 要执行的SQL语句
     * @param params 参数数组
     * @return 如果查询不到记录，返回null
     * @throws SQLException SQL异常
     */
    public String[] find(String sql, Object... params) throws SQLException {
        return run.query(conn, sql, new StringArrayHandler(), params);
    }
    
    /**
     * 查询所有记录到list中
     * @param sql 要执行的SQL语句
     * @return 如果没有查询结果，返回容量为0的list
     * @throws SQLException SQL异常
     */
    public List<String[]> query(String sql) throws SQLException {
        return query(sql, (Object[]) null);
    }
    
    /**
     * 查询所有记录到list中
     * @param sql 要执行的SQL语句
     * @param param 参数对象
     * @return 如果没有查询结果，返回容量为0的list
     * @throws SQLException SQL异常
     */
    public List<String[]> query(String sql, Object param) throws SQLException {
        return query(sql, new Object[] { param });
    }
    
    /**
     * 查询所有记录到list中
     * @param sql 要执行的SQL语句
     * @param params 参数数组对象
     * @return 如果没有查询结果，返回容量为0的list
     * @throws SQLException SQL异常
     */
    public List<String[]> query(String sql, Object... params) throws SQLException {
        return run.query(conn, sql, new StringArrayListHandler(), params);
    }

    
    /**
     * 关闭连接
     */
    public void close() {
        DbUtils.closeQuietly(conn);
        conn = null;
    }
}